#include "tcpserver.h"

TcpServer::TcpServer(QObject *parent) : QObject(parent)
{

}

void TcpServer::init()
{
    m_server = new QTcpServer;
    m_tcpServer = new QTcpServer;
    m_sendpayloadSize=64*1024;
    connect(m_server,SIGNAL(newConnection()),this,SLOT(newClientConnect()));
    connect(m_tcpServer,SIGNAL(newConnection()),this,SLOT(acceptConnection()));
}

void TcpServer::acceptConnection(){
    m_filesocket=m_tcpServer->nextPendingConnection();
    connect(m_filesocket,SIGNAL(bytesWritten(qint64)),this,SLOT(updateClientProgress(qint64)));
    connect(m_filesocket,SIGNAL(readyRead()),this,SLOT(updateServerProgress()));
    connect(m_filesocket,SIGNAL(error(QAbstractSocket::SocketError)),this,SLOT(displayError(QAbstractSocket::SocketError)));
}
void TcpServer::updateServerProgress(){
    QDataStream in(m_filesocket);
    in.setVersion(QDataStream::Qt_5_7);
    // 如果接收到的数据小于16个字节，保存到来的文件头结构
    if (m_bytesReceived<=sizeof(qint64)*2){
        if((m_filesocket->bytesAvailable()>=sizeof(qint64)*2)&&(m_fileNameSize==0)){
            // 接收数据总大小信息和文件名大小信息
            in>>m_totalBytes>>m_fileNameSize;
            m_bytesReceived +=sizeof(qint64)*2;
        }
        if((m_filesocket->bytesAvailable()>=m_fileNameSize)&&(m_fileNameSize!=0)){
            // 接收文件名，并建立文件
            in>>m_fileName;
            qDebug()<<tr("recv file %1").arg(m_fileName);
            m_bytesReceived+=m_fileNameSize;
            m_localFile = new QFile(m_fileName);
            if (!m_localFile->open(QFile::WriteOnly)){
                qDebug() << "server: open file error!";
                return;
            }
        }
        else{
            return;
        }
    }
    // 如果接收的数据小于总数据，那么写入文件
    if(m_bytesReceived<m_totalBytes) {
        m_bytesReceived+=m_filesocket->bytesAvailable();
        m_inBlock = m_filesocket->readAll();
        m_localFile->write(m_inBlock);
        m_inBlock.resize(0);
        qDebug()<<tr("recv file %1").arg(m_fileName);
    }

    // 接收数据完成时
    if (m_bytesReceived==m_totalBytes){
        //m_filesocket->close();
        m_localFile->close();
        m_totalBytes=0;
        m_bytesReceived=0;
        m_fileNameSize=0;
        qDebug()<<tr("recv file %1 sucess").arg(m_fileName);
    }
}

void TcpServer::displayError(QAbstractSocket::SocketError socketError){
    Q_UNUSED(socketError)
    qDebug()<<m_filesocket->errorString();
    m_filesocket->close();
}



void TcpServer::startListen(QString ip, QString port)
{
    if(m_server->listen(QHostAddress::Any,port.toInt()))
        qDebug() << "listen ok";
    else
        qDebug() << "listen err "<<m_server->errorString();
    if(!m_tcpServer->listen(QHostAddress::LocalHost,6666)){
        qDebug()<<m_tcpServer->errorString();
    }
    m_totalBytes=0;
    m_bytesReceived=0;
    m_fileNameSize=0;
}

void TcpServer::sendData(const QString &data)
{
    TcpProtocol tcpProtocol;
    tcpProtocol.data = data.toUtf8().data();
    QByteArray arr = tcpProtocol.getStream();
    //for(int i =0 ;i <100 ;i++){
        m_socket->write(arr);
        m_socket->waitForBytesWritten();
    //}

}

void TcpServer::sendFile(const QString &filepath, int seek)
{
    m_sendfileName = filepath;
    startTransfer();
}

void TcpServer::newClientConnect()
{
    m_socket = m_server->nextPendingConnection();
    connect(m_socket,SIGNAL(readyRead()),this,SLOT(readMessage()));
    connect(m_socket,SIGNAL(disconnected()),this,SLOT(disConnect()));
}

void TcpServer::readMessage()
{
    //缓冲区没有数据，直接无视
    if( m_socket->bytesAvailable() <= 0 )
    {
        return;
    }

    //临时获得从缓存区取出来的数据，但是不确定每次取出来的是多少。
    QByteArray buffer;
    //如果是信号readyRead触发的，使用readAll时会一次把这一次可用的数据全总读取出来
    //所以使用while(m_tcpClient->bytesAvailable())意义不大，其实只执行一次。
    buffer = m_socket->readAll();

    //上次缓存加上这次数据

    m_buffer.append(buffer);
    uint32_t size ;
    int totalLen = m_buffer.size();

    while( totalLen )
    {
        //与QDataStream绑定，方便操作。
        QDataStream packet(m_buffer);

        //不够包头的数据直接就不处理。
        if( totalLen < OtherSize )
        {
            break;
        }
        packet >> size ;
        //如果不够长度等够了在来解析
        if( totalLen < size )
        {
            break;
        }
        TcpProtocol p(m_buffer);
        if(p.cmd == 1){
            signReadyRead(p);
        }else if(p.cmd == 2){
            save2File(p);
            if(p.isLastPack != 1)
                sendReadFileData(p);
        }else if(p.cmd == 3){
            if(p.seek >= m_file.size()){
                m_file.close();
                return;
            }
            sendfile(m_filePath,p.seek);
        }

        //缓存多余的数据
        buffer = m_buffer.right(totalLen - size);

        //更新长度
        totalLen = buffer.size();
        if(buffer.size() != 0){
            qDebug()<<"黏包";
        }
        //更新多余数据
        m_buffer = buffer;
    }
}

void TcpServer::disConnect()
{

}

void TcpServer::save2File(TcpProtocol tcpProtocol)
{
    if(tcpProtocol.seek == 0){
        m_file.close();
        m_file.setFileName("./temp.txt");
        m_file.open(QFile::WriteOnly);
    }
    m_file.seek(tcpProtocol.seek);
    m_file.write(tcpProtocol.data.data());

    if(tcpProtocol.isLastPack == 1){
        m_file.close();
        qDebug()<<"file save sucess";
    }
}

void TcpServer::sendReadFileData(TcpProtocol tcpProtocol)
{
    TcpProtocol sendtcpProtocol;
    sendtcpProtocol.cmd = 3;
    sendtcpProtocol.seek = tcpProtocol.seek + SendFileBufferSize;
    QByteArray arr = sendtcpProtocol.getStream();
    m_socket->write(arr);
    m_socket->waitForBytesWritten();
}

void TcpServer::sendfile(const QString &filepath, int seek)
{
    TcpProtocol tcpProtocol;
    tcpProtocol.cmd = 2;
    m_file.seek(seek);
    tcpProtocol.data = m_file.read(SendFileBufferSize);
    tcpProtocol.seek = seek;
    qDebug()<<"seek +readsize = "<<seek + tcpProtocol.data.size()<<" m_file.size() = "<<m_file.size();
    if(seek +tcpProtocol.data.size() >=  m_file.size()){
        tcpProtocol.isLastPack = 1;
        m_file.close();
    }
    QByteArray data = tcpProtocol.getStream();
    m_socket->write(data);
    m_socket->waitForBytesWritten();
}

void TcpServer::startTransfer()
{
    m_sendlocalFile=new QFile(m_sendfileName);
    if(!m_sendlocalFile->open(QFile::ReadOnly)){
        qDebug()<<"client：open file error!";
        return;
    }
    m_sendtotalBytes=m_sendlocalFile->size();
    QDataStream sendOut(&m_sendoutBlock,QIODevice::WriteOnly);
    sendOut.setVersion(QDataStream::Qt_5_7);
    QString currentFileName=m_sendfileName.right(m_sendfileName.size()-m_sendfileName.lastIndexOf('/')-1);
    //文件总大小、文件名大小、文件名
    sendOut<<qint64(0)<<qint64(0)<<currentFileName;
    m_sendtotalBytes+=m_sendoutBlock.size();
    sendOut.device()->seek(0);
    sendOut<<m_sendtotalBytes<<qint64(m_sendoutBlock.size()-sizeof(qint64)*2);
    m_sendbytesToWrite=m_sendtotalBytes-m_filesocket->write(m_sendoutBlock);
    m_sendoutBlock.resize(0);

}

void TcpServer::updateClientProgress(qint64 numBytes)
{
    m_sendbytesWritten+=(int)numBytes;
    if(m_sendbytesToWrite>0){
        m_sendoutBlock=m_sendlocalFile->read(qMin(m_sendbytesToWrite,m_sendpayloadSize));
        m_sendbytesToWrite-=(int)m_filesocket->write(m_sendoutBlock);
        m_sendoutBlock.resize(0);
        qDebug()<<__FUNCTION__<<"numBytes = "<<numBytes;
    }else{
        m_sendlocalFile->close();
    }
    if(m_sendbytesWritten==m_sendtotalBytes){
        m_sendlocalFile->close();
    }

}
